/**
 * 原型拓展上的入口方法名
 */
const MOUNT_ENTRY_FUNCTION = 'loop'

/**
 * bot 名称的后缀，会加到指定的名称后
 * 防止不小心覆盖 Memory 的关键字段
 */
const BOT_NAME_SUFFIX = 'Framework'

/**
 * 默认的 bot 名称
 */
const DEFAULT_BOT_NAME = `noahwang${BOT_NAME_SUFFIX}`

export default class Entrypoint {
    /**
     * 该 bot 的名称
     */
    public readonly name: string = DEFAULT_BOT_NAME

    private _loopObjects: ILoopObjects = {}

    constructor({ mountList }: CreateOptions = {}) {
        if (mountList) {
            mountList.map(group => this.mount(...group))
        }
    }

    /**
     * 默认的 Memory 缓存存放处
     */
    private _cachedMemory: Memory

    /**
     * 默认的内存缓存器
     * 来源 @see https://screeps.slack.com/files/U33SKDU0P/F5GKDBBAA/Memory_Cache.js?origin_team=T0HJCPP9T&origin_channel=C2G22RFPF
     */
    private _memoryCacher: MemoryCacher = next => {
        if (this._cachedMemory) {
            delete global.Memory;
            global.Memory = this._cachedMemory
        } else {
            this._cachedMemory = Memory
        }

        next()

        if (global.Memory) {
            const globalMemory = JSON.stringify(global.Memory)
            if (globalMemory) {
                RawMemory.set(globalMemory)
            }
        }
    }

    /**
     * 设置新的内存缓存器
     * 设置为空则不使用内存缓存
     *
     * @danger 请务必执行 next 方法！不然框架将无法正常使用
     */
    set memoryCacher(newCatcher: MemoryCacher) {
        this._memoryCacher = newCatcher
    }

    /**
     * 默认的异常捕获
     */
    private _catcher: ErrorCatcher = next => {
        try {
            next()
        }
        catch (e) {
            console.log(`<span style="color:#ef9a9a">${e}</sapn>`)
            Game.notify(e)
        }
    }

    /**
     * 设置新的异常捕获器
     * 不允许设置为空
     *
     * @danger 请务必执行 next 方法！不然框架将无法正常使用
     */
    set catcher(newCatcher: ErrorCatcher) {
        if (!newCatcher) return
        this._catcher = newCatcher
    }

    /**
     * 挂载原型拓展
     *
     * @param targetClass 要挂载到的类
     * @param extensionClass 包含拓展的类
     */
    public mount(targetClass: AnyClass, extensionClass: AnyClass): Entrypoint {
        // 进行挂载
        Object.getOwnPropertyNames(extensionClass.prototype).map(prop => {
            targetClass.prototype[prop] = extensionClass.prototype[prop]
        })
        return this
    }

    public register(loopObject: ILoopObject) {
        if (!(loopObject.name in this._loopObjects)) {
            this._loopObjects[loopObject.name] = loopObject
            // console.log(`Entrypoint.register ${loopObject.name} success`)
        }
        else {
            console.log(`Entrypoint.register ${loopObject.name} failed, already registered`)
        }
    }

    public unregister(loopObjectName: string) {
        if (loopObjectName in this._loopObjects) {
            delete this._loopObjects[loopObjectName]
            console.log(`Entrypoint.unregister ${loopObjectName} success`)
        }
        else {
            console.log(`Entrypoint.unregister ${loopObjectName} failed, not found`)
        }
    }

    private _doloopObjects(phase: string) {
        for (const name in this._loopObjects) {
            const loopObject: ILoopObject = this._loopObjects[name]
            loopObject.loop(phase)
        }
    }

    public loop(): Entrypoint {
        // // 有内存缓存的话就包裹一下，否则就直接运行
        if (this._memoryCacher) this._memoryCacher(this._loop.bind(this))
        else this._loop()

        return this
    }

    private _loop() {

        console.log(`-----${Game.time}-----`)

        if (!global._mountComplete) this.onGlobalReset()

        // tickStart
        this._doloopObjects('tickStart')

        // do
        this._doloopObjects('do')

        // // Automatically delete memory of missing creeps
        // for (const name in Memory.creeps) {
        //     if (!(name in Game.creeps)) {
        //     delete Memory.creeps[name];
        //     }
        // }

        // afterWork
        this._doloopObjects('afterWork')

        // tickEnd
        this._doloopObjects('tickEnd')

        // console.log('[loop]', Game.cpu.getUsed())
        // const atkCreep = Game.creeps['ATK_0']
        // if (atkCreep) {
        //     // const roomName = 'E34S48'
        //     // atkCreep.goTo(new RoomPosition(25,25, roomName))
        //     if (!atkCreep.memory.targetId) {
        //         const spawn = atkCreep.room[STRUCTURE_TOWER]
        //         if (spawn && spawn[0]) atkCreep.memory.targetId = spawn[0].id
        //     }
        //     else {
        //         const target = Game.getObjectById(atkCreep.memory.targetId) as StructureTower
        //         const status = atkCreep.dismantle(target)
        //         if (status == ERR_NOT_IN_RANGE) {
        //             atkCreep.goTo(target.pos)
        //         }
        //         else if (status == OK) {
        //             delete atkCreep.memory.targetId
        //         }
        //     }
        // }
    }


    /**
     * 当全局重置时触发
     */
    private onGlobalReset() {
        this._doloopObjects('reset')
        global._mountComplete = true

        // 检查是否是第一次全局重置
        if (!Memory[this.name]) {
            this._doloopObjects('born')
            Memory[this.name] = true
        }
    }

    /**
     * 在异常捕获下执行对象的入口方法
     * @param gameItem 要调用入口方法的游戏对象
     */
    private doWithCatcher(gameItem): void {
        this._catcher(gameItem[MOUNT_ENTRY_FUNCTION].bind(gameItem))
    }
}
